/*
 * graph2D
 * Copyright (c) 2009 Shun Moriya <shun@mnu.sakura.ne.jp>
 *
 * The MIT License
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
 * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
 * THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#if !defined(___GRAPH2D_TEXTURE_H___)
#define ___GRAPH2D_TEXTURE_H___

#include "graphicDevice.h"
#include "vector2.h"
#include <string>
#include <mana_stream.h>

namespace Graph2D
{
	class Texture
	{
		DISALLOW_COPY_AND_ASSIGN(Texture);

		friend class TextureContainer;

		enum Constants
		{
			PVRTC_FLAG_TYPE_RGBA4444 = 16,
			PVRTC_FLAG_TYPE_RGBA1555 = 17,
			PVRTC_FLAG_TYPE_RGBA8888 = 18,
			PVRTC_FLAG_TYPE_RGB565 = 19,
			PVRTC_FLAG_TYPE_RGB888 = 21,
			PVRTC_FLAG_TYPE_I8 = 22,
			PVRTC_FLAG_TYPE_AI88 = 23,
			PVRTC_FLAG_TYPE_PVRTC_2 = 24,
			PVRTC_FLAG_TYPE_PVRTC_4 = 25,
			PVRTC_FLAG_TYPE_A8 = 27,
			PVRTC_FLAG_TYPE_MASK = 0xff,
			PVRTC_MAX_SURFACES = 16
		};

		struct Header
		{
			unsigned int headerSize;
			unsigned int height;
			unsigned int width;
			unsigned int numMipmaps;
			unsigned int flags;
			unsigned int dataSize;
			unsigned int bpp;
			unsigned int bitmaskRed;
			unsigned int bitmaskGreen;
			unsigned int bitmaskBlue;
			unsigned int bitmaskAlpha;
			unsigned int tag;
			unsigned int numSurfaces;
		};

		struct Surface
		{
			GLuint size;
			const void* bits;
		};

		static const char PVRIdentifier[4];
		static GLuint lastBindTextureName;

	private:
		/*!
		 * @brief	コンストラクタ
		 */
		Texture();

		/*!
		 * @brief	デストラクタ
		 */
		virtual ~Texture();

		/*!
		 * @brief	テクスチャデータを読み込む
		 * @param[in]	buffer		テクスチャデータ
		 * @retval		true		読み込み成功
		 * @retval		false		読み込み失敗
		 */
		bool load(const void* buffer);

		/*!
		 * @brief	テクスチャファイルを読み込む
		 * @param[in]	filename	テクスチャファイル名
		 * @retval		true		読み込み成功
		 * @retval		false		読み込み失敗
		 */
		bool load(const char* filename);

		/*!
		 * @brief	テクスチャファイルを読み込む
		 * @param[in]	filename	テクスチャファイル名
		 * @retval		true		読み込み成功
		 * @retval		false		読み込み失敗
		 */
		bool load(const std::string& filename);

		void retain();

		/*!
		 * @brief	テクスチャを解放
		 * @return	現在の参照数
		 */
		GLushort unload();

	public:
		/*!
		 * @brief	シリアライズ
		 */
		void serialize(mana_stream* stream) const;

		/*!
		 * @brief	デシリアライズ
		 */
		void deserialize(mana_stream* stream);

		/*!
		 * @brief	テクスチャをバインドする
		 */
		void bind();

		/*!
		 * @brief	テクスチャをアンバインドする
		 */
		static void unbind();

		/*!
		 * @brief	テクスチャの幅を取得
		 * @return	テクスチャの幅
		 */
		GLuint getWidth() const
		{
			return width;
		}

		/*!
		 * @brief	テクスチャの高さを取得
		 * @return	テクスチャの高さ
		 */
		GLuint getHeight() const
		{
			return height;
		}

		/*!
		 * @brief	テクスチャのフォーマットを取得
		 * @return	テクスチャのフォーマット
		 */
		GLenum getFormat() const
		{
			return format;
		}

		/*!
		 * @brief	テクスチャにアルファチャンネルがあるか取得
		 * @return	trueならばアルファチャンネルがあります
		 */
		bool hasAlpha() const
		{
			return alpha;
		}

		/*!
		 * @brief	テクスチャのサーフェイス数を取得
		 * @return	テクスチャのサーフェイス数
		 */
		GLuint getSurfaceCount() const
		{
			return numSurfaces;
		}

		/*!
		 * @brief	テクスチャ番号を取得
		 * @return	テクスチャ番号
		 */
		GLuint getName() const
		{
			return name;
		}

		/*!
		 * @brief	テクスチャサイズを取得
		 * @return	テクスチャサイズ
		 */
		Vector2 getSize() const
		{
			return Vector2(static_cast<float>(getWidth()), static_cast<float>(getHeight()));
		}

		/*!
		 * @brief
		 */
		Vector2 getTextureSize() const
		{
			return Vector2(static_cast<float>(getWidth()), static_cast<float>(getHeight()));
		}

		/*!
		 * @brief
		 */
		Vector2 getMaxSize() const
		{
			return Vector2(static_cast<float>(getWidth()), static_cast<float>(getHeight()));
		}

	private:
		GLushort width;							//!< @brief 幅
		GLushort height;						//!< @brief 高さ
		GLuint name;							//!< @brief テクスチャ名
		GLenum format;							//!< @brief テクスチャフォーマット番号
		Surface surfaces[PVRTC_MAX_SURFACES];	//!< @brief サーフェイス情報
		GLushort numSurfaces;					//!< @brief サーフェイス枚数
		GLushort referenceCount;				//!< @brief 参照カウンター
		bool alpha;								//!< @brief アルファ情報フラグ
	};
}

#endif
